package com.dmz.task.utils;

import com.dmz.task.constant.GlobalConstant;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * @author lee
 */
public class FileUtils {

    // 假设我们只允许访问 /app/data 目录下的文件
    private static final Path BASE_DIR = Paths.get(GlobalConstant.BASE_DIR).toAbsolutePath().normalize();

    public static File getSafeFile(String userInputFilename) throws IOException {
        // 1. 基本校验：输入不能为空或为空字符串
        if (userInputFilename == null || userInputFilename.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        // 2. 将输入转换为Path对象并规范化，消除其中的 `../` 和 `./`
        Path userPath = Paths.get(userInputFilename).normalize();

        // 3. 防止“绝对路径”攻击（例如，用户输入 `/etc/passwd`）
        // 确保规范化后的用户路径不是绝对路径。如果它是绝对路径，下面的resolve方法会直接使用它，从而绕过我们的基础目录。
        if (userPath.isAbsolute()) {
            throw new IllegalArgumentException("文件名不能为绝对路径");
        }

        // 4. 将用户输入解析（Resolve）到基础目录，并再次规范化以确保安全
        Path resolvedPath = BASE_DIR.resolve(userPath).normalize();

        // 5. 至关重要的最终校验：确保解析后的路径仍然在基础目录之内！
        if (!resolvedPath.startsWith(BASE_DIR)) {
            // 这是一个安全异常，说明有人试图通过类似 `../../etc/passwd` 的输入进行攻击
            // 尽管经过了normalize，但再检查一次是防御深度嵌套攻击的好习惯
            throw new IllegalArgumentException("非法尝试访问基础目录之外的文件");
        }

        // 6. 现在，可以安全地使用这个文件对象了
        File safeFile = resolvedPath.toFile();

        // 可选：检查文件是否存在，是否是文件（而不是目录）等，根据你的业务逻辑来
        if (!safeFile.exists()) {
            throw new FileNotFoundException("文件不存在");
        }
        if (safeFile.isDirectory()) { // 如果你的API不允许操作目录，加上这个检查
            throw new IllegalArgumentException("不能访问目录");
        }

        return safeFile;
    }
}
